﻿/*
 * iec104.hpp
 *
 *  Created on: 2017年3月20日
 *      Author: work
 */

#ifndef _DM_PROTOCOL_IEC104_HPP_
#define _DM_PROTOCOL_IEC104_HPP_

#include <dm/export.hpp>
#ifndef DM_API_PROTOCOL
#define DM_API_PROTOCOL DM_API_IMPORT
#endif

#include <dm/fixed_counter.hpp>
#include <dm/protocol/protocol.hpp>
#include <dm/protocol/frame104ldu.hpp>
#include <dm/protocol/frame104apdu.hpp>

namespace dm{
namespace protocol{

/**
 * IEC104基类
 * 实现了104框架，并实现链路层交互过程
 */
class DM_API_PROTOCOL CIec104:virtual public CProtocol{
public:
	typedef dm::protocol::CFrame104Ldu frame_104_t;
	typedef dm::protocol::CFrame104Apdu frame_apdu_t;
	typedef dm::TCFixedCounter<dm::uint16,0x8000> count_t;	// 计数器类
	typedef dm::uint32 objaddr_t;

	enum{
		MaxLen_Asdu = 256,
		MaxLen_Buf = 256,

		// 系统运行参数 --------

		// 允许连续错误序号帧数
		MaxNum_Err_SFrame = 5
	};

	CIec104();
	virtual ~CIec104();

	frame_t& getRxFrame();
	const frame_t& getTxFrame();

	EAction timedRefresh( const ts_t& ts,const rts_t& rts );

	EAction dealRxFrame( const ts_t& ts,const rts_t& rts );

	virtual void reset( const ts_t& ts,const rts_t& rts );

	virtual bool setTask_call( const ts_t& ts,const rts_t& rts,const group_t& group=0,const sec_t& timeout=0 );
	virtual bool setTask_syncClock( const ts_t& ts,const rts_t& rts,const sec_t& timeout = 0 );
	virtual bool setTask_remoteControl( const ts_t& ts,const rts_t& rts,const rmtctl_t& rc,const index_t& addr,const sec_t& timeout=0 );
	virtual bool setTask_parasSetUint8( const ts_t& ts,const rts_t& rts,const index_t& addr,const index_t& size,const dm::uint8* data,const sec_t& timeout=0 );
	virtual bool setTask_parasSetInt8( const ts_t& ts,const rts_t& rts,const index_t& addr,const index_t& size,const dm::int8* data,const sec_t& timeout=0 );
	virtual bool setTask_parasSetUint16( const ts_t& ts,const rts_t& rts,const index_t& addr,const index_t& size,const dm::uint16* data,const sec_t& timeout=0 );
	virtual bool setTask_parasSetInt16( const ts_t& ts,const rts_t& rts,const index_t& addr,const index_t& size,const dm::int16* data,const sec_t& timeout=0 );
	virtual bool setTask_parasSetUint32( const ts_t& ts,const rts_t& rts,const index_t& addr,const index_t& size,const dm::uint32* data,const sec_t& timeout=0 );
	virtual bool setTask_parasSetInt32( const ts_t& ts,const rts_t& rts,const index_t& addr,const index_t& size,const dm::int32* data,const sec_t& timeout=0 );
	virtual bool setTask_parasSetUint64( const ts_t& ts,const rts_t& rts,const index_t& addr,const index_t& size,const dm::uint64* data,const sec_t& timeout=0 );
	virtual bool setTask_parasSetInt64( const ts_t& ts,const rts_t& rts,const index_t& addr,const index_t& size,const dm::int64* data,const sec_t& timeout=0 );
	virtual bool setTask_parasSetFloat32( const ts_t& ts,const rts_t& rts,const index_t& addr,const index_t& size,const dm::float32* data,const sec_t& timeout=0 );
	virtual bool setTask_parasSetFloat64( const ts_t& ts,const rts_t& rts,const index_t& addr,const index_t& size,const dm::float64* data,const sec_t& timeout=0 );
	virtual bool setTask_parasGet( const ts_t& ts,const rts_t& rts,const index_t& addr,const index_t& size,const sec_t& timeout=0 );
	virtual bool setTask_syncData( const ts_t& ts,const rts_t& rts,const sync_t& type,const sec_t& timeout=0 );

	inline const bool& isDtStarted()const{
		return m_dtStarted;
	}

	inline bool isDtStoped()const{
		return !isDtStarted();
	}

	inline void setAutoStatrtDt( const bool& b ){
		m_autoStartDt = b;
	}

	inline const dm::uint16& getCommonAddr()const{
		return m_commonAddr;
	}

	inline void setCommonAddr( const dm::uint16& addr ){
		m_commonAddr = addr;
	}

	inline const objaddr_t& getYxBase()const{
		return m_baseOfYx;
	}

	inline void setYxBase( const objaddr_t& addr ){
		m_baseOfYx = addr;
	}

	inline const objaddr_t& getYcBase()const{
		return m_baseOfYc;
	}

	inline void setYcBase( const objaddr_t& addr ){
		m_baseOfYc = addr;
	}

	inline const objaddr_t& getYkBase()const{
		return m_baseOfYk;
	}

	inline void setYkBase( const objaddr_t& addr ){
		m_baseOfYk = addr;
	}

	inline const objaddr_t& getKwhBase()const{
		return m_baseOfKwh;
	}

	inline void setKwhBase( const objaddr_t& addr ){
		m_baseOfKwh = addr;
	}

	inline const dm::uint16& getK()const{
		return m_k;
	}

	inline void setK( dm::uint16 k ){
		m_k = k;
	}

	inline const dm::uint16& getW()const{
		return m_w;
	}

	inline void setW( dm::uint16 w ){
		m_w = w;
	}

	inline const dm::uint16& getT0()const{
		return m_t0;
	}

	inline void setT0( dm::uint16 t0 ){
		m_t0 = t0;
	}

	inline const dm::uint16& getT1()const{
		return m_t1;
	}

	inline void setT1( dm::uint16 t1 ){
		m_t1 = t1;
	}

	inline const dm::uint16& getT2()const{
		return m_t2;
	}

	inline void setT2( dm::uint16 t2 ){
		m_t2 = t2;
	}

	inline const dm::uint16& getT3()const{
		return m_t3;
	}

	inline void setT3( dm::uint16 t3 ){
		m_t3 = t3;
	}

	bool setLenOfAsduAddr( dm::uint8 l );
	bool setLenOfInfoAddr( dm::uint8 l );
	bool setLenOfTransCause( dm::uint8 l );
	void setMaxLenOfApdu( dm::uint16 l );
protected:
	frame_104_t* genRxTempFrame();
	frame_104_t* genTxTempFrame();

	EAction taskLink( const ts_t& ts,const rts_t& rts );

	EAction sendIFrame_error( const frame_apdu_t& rf,frame_apdu_t& tf,const frame_apdu_t::ECause& cause );

	EAction sendUFrame_startDt();

	// 是否可以发送应用帧
	inline bool ifCanSendIFrame()const{
		return (m_dtStarted && (m_ssq-m_ssqCfm)<m_k);
	}

	bool ifNeedSendSFrame()const;

	EAction linkTest();

	EAction dealRxUFrame( const ts_t& ts,const rts_t& rts );

	void dealRxSFrame( const count_t& seq,const ts_t& ts,const rts_t& rts );
	EAction dealRxIFrame( const ts_t& ts,const rts_t& rts );

	virtual EAction dealStopDtConf( const ts_t& ts,const rts_t& rts )=0;
	virtual EAction dealStopDt( const ts_t& ts,const rts_t& rts )=0;
	virtual EAction dealStartDtConf( const ts_t& ts,const rts_t& rts )=0;
	virtual EAction dealStartDt( const ts_t& ts,const rts_t& rts )=0;

	EAction dealTestFr( const ts_t& ts,const rts_t& rts );
	EAction askTestFr( const ts_t& ts,const rts_t& rts );

	EAction dealAsdu( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );

	// 子类应该继承这些函数中选用的数据类型，来处理接收到的数据。默认是不处理
	virtual EAction dealAsdu_M_SP_NA_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_M_DP_NA_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_M_ST_NA_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_M_BO_NA_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_M_ME_NA_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_M_ME_NB_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_M_ME_NC_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_M_IT_NA_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_M_PS_NA_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_M_ME_ND_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );

	virtual EAction dealAsdu_M_SP_TB_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_M_DP_TB_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_M_ST_TB_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_M_BO_TB_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_M_ME_TD_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_M_ME_TE_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_M_ME_TF_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_M_IT_TB_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_M_EP_TD_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_M_EP_TE_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_M_EP_TF_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );

	virtual EAction dealAsdu_C_SC_NA_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_C_DC_NA_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_C_RC_NA_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_C_SE_NA_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_C_SE_NB_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_C_SE_NC_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_C_BO_NA_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );

	virtual EAction dealAsdu_C_SC_NA_1_7( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_C_DC_NA_1_7( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_C_RC_NA_1_7( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_C_SE_TA_1_7( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_C_SE_TB_1_7( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_C_SE_TC_1_7( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_C_BO_NA_1_7( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );

	virtual EAction dealAsdu_M_EI_NA_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );

	virtual EAction dealAsdu_C_IC_NA_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_C_CI_NA_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_C_RD_NA_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_C_CS_NA_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_C_RP_NA_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_C_TS_NA_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_P_ME_NA_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_P_ME_NB_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_P_ME_NC_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_P_AC_NA_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );

	virtual EAction dealAsdu_F_FR_NA_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_F_SR_NA_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_F_SC_NA_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_F_LS_NA_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_F_AF_NA_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_F_SG_NA_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );
	virtual EAction dealAsdu_F_DR_NA_1( const frame_apdu_t& rf,frame_apdu_t& tf,const ts_t& ts,const rts_t& rts );

	/**
	 * 需要对接收到序号进行确认
	 * 长时间没有新帧，或者对方有多帧没有被确认
	 * @param txFrame
	 * @param deadline
	 * @return
	 */
	virtual EAction needConfirmRsq();

	// 设置发送序号
	void setSendSeq();

	// 设置接收序号
	void setRecvConfSeq( const ts_t& ts,const rts_t& rts );

	virtual void getCurrentTime( frame_apdu_t::UCp56Time2a& t )const;
	virtual bool setCurrentTime( const frame_apdu_t::UCp56Time2a& t );

	inline frame_104_t& rxFrame(){
		return *m_rxFrame;
	}

	inline frame_104_t& txFrame(){
		return *m_txFrame;
	}

private:
	void setUpIFrame( const ts_t& ts,const rts_t& rts );

protected:
	// 发送计数器,初始为0 每次发送数据后需要累加1
	count_t	m_ssq;

	// 接收计数器,初始为0 表示希望对端下次发送的序号
	count_t	m_rsq;

	// 被对方确认过的发送序号 初始0
	count_t	m_ssqCfm;

	// 确认过的接收序号 初始0x7FFF
	count_t	m_rsqCfm;

	// 上次被对端确认序号时间
	rts_t	m_lastConffedTime;

	// 上次对对端确认序号时间
	rts_t	m_lastSendConfirmTime;

	// 上次接收对端数据
	rts_t	m_lastRecvDataTime;

	// 是否在测试链路
	bool	m_ifTestingLink;

	// 收到错误帧计数
	int m_errFrameCount;

	// 数据传输状态
	bool m_dtStarted;

	// 是否自动开启数据传输
	bool m_autoStartDt;
	bool m_ifStartingDt;	// 是否正在发送启动帧

	dm::uint16 m_commonAddr;

	objaddr_t m_baseOfYx;
	objaddr_t m_baseOfYc;
	objaddr_t m_baseOfYk;
	objaddr_t m_baseOfKwh;

	frame_104_t* m_rxFrame;	// 接收帧，用于解析的帧
	frame_104_t* m_txFrame;	// 发送帧，用于发送的帧

	dm::uint16 m_k;
	dm::uint16 m_w;
	dm::uint16 m_t0;
	dm::uint16 m_t1;
	dm::uint16 m_t2;
	dm::uint16 m_t3;
};

}
}



#endif /* INCLUDE_DM_PROTOCOL_IEC104_HPP_ */
